// PjStatsLocationTemperatureHourServiceImpl.java
package site.isscloud.project.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;

import site.isscloud.project.domain.PjStatsLocationTemperatureMinute;
import site.isscloud.project.domain.PjStatsLocationTemperatureHour;
import site.isscloud.project.mapper.PjStatsLocationTemperatureMinuteMapper;
import site.isscloud.project.mapper.PjStatsLocationTemperatureHourMapper;
import site.isscloud.project.service.IPjStatsLocationTemperatureHourService;

/**
 * 空间位置温度小时统计Service业务层处理
 */
@Service
public class PjStatsLocationTemperatureHourServiceImpl implements IPjStatsLocationTemperatureHourService {

    private static final Logger log = LoggerFactory.getLogger(PjStatsLocationTemperatureHourServiceImpl.class);
    // 专门用于统计日志的Logger
    private static final Logger statisticLog = LoggerFactory.getLogger("statistic");

    @Autowired
    private PjStatsLocationTemperatureMinuteMapper pjStatsLocationTemperatureMinuteMapper;

    @Autowired
    private PjStatsLocationTemperatureHourMapper pjStatsLocationTemperatureHourMapper;

    // 在 PjStatsLocationTemperatureHourServiceImpl 类中添加
    @Override
    public void generateLocationTemperatureHourStats() {
        // 计算上一小时的时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, -1);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);

        Date statTime = calendar.getTime();

        statisticLog.info("自动计算小时统计时间: {}", statTime);

        // 调用原有的统计方法
        generateLocationTemperatureHourStats(statTime);
    }

    /**
     * 生成空间位置温度小时统计数据（基于分钟统计数据）
     */
    @Override
    public void generateLocationTemperatureHourStats(Date statTime) {
        statisticLog.info("=== 开始生成空间位置温度小时统计数据 ===");
        statisticLog.info("统计时间: {}", statTime);
        long startTime = System.currentTimeMillis();

        int totalSuccessCount = 0;
        int totalFailCount = 0;

        try {
            // 计算前一小时的时间范围
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(statTime);
            Date hourStart = calendar.getTime();  // statHour本身就是小时的开始时间

            calendar.add(Calendar.HOUR_OF_DAY, 1);
            calendar.add(Calendar.MILLISECOND, -1);
            Date hourEnd = calendar.getTime();

            statisticLog.info("小时统计时间范围: {} 到 {}", hourStart, hourEnd);

            // 1. 获取前一小时的所有分钟统计数据
            statisticLog.info("步骤1: 获取小时范围内的分钟统计数据");
            List<PjStatsLocationTemperatureMinute> minuteStats =
                    pjStatsLocationTemperatureMinuteMapper.selectByTimeRange(
                            hourStart.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                            hourEnd.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
                    );
            statisticLog.info("获取到 {} 条分钟统计数据", minuteStats.size());

            if (minuteStats.isEmpty()) {
                statisticLog.warn("未找到指定时间范围的分钟统计数据: {} - {}", hourStart, hourEnd);
                return;
            }

            // 2. 按空间编码分组（只按lc_code分组）
            statisticLog.info("步骤2: 按空间编码分组分钟数据");
            Map<String, List<PjStatsLocationTemperatureMinute>> statsByLocation = minuteStats.stream()
                    .collect(Collectors.groupingBy(PjStatsLocationTemperatureMinute::getLcCode));

            statisticLog.info("共分组成 {} 个空间位置", statsByLocation.size());

            // 3. 为每个空间位置生成小时统计
            statisticLog.info("步骤3: 生成小时统计数据");
            List<PjStatsLocationTemperatureHour> hourStats = new ArrayList<>();

            for (Map.Entry<String, List<PjStatsLocationTemperatureMinute>> entry : statsByLocation.entrySet()) {
                String lcCode = entry.getKey();
                List<PjStatsLocationTemperatureMinute> locationMinuteStats = entry.getValue();

                try {
                    if (locationMinuteStats.isEmpty()) {
                        continue;
                    }

                    // 计算小时统计值
                    PjStatsLocationTemperatureHour hourStat = calculateHourStatsFromMinutes(
                            locationMinuteStats, hourStart);

                    if (hourStat != null) {
                        hourStats.add(hourStat);
                        totalSuccessCount++;

                        statisticLog.debug("小时统计生成成功 - 空间编码: {}, 数据点: {}",
                                lcCode, locationMinuteStats.size());
                    } else {
                        totalFailCount++;
                        statisticLog.warn("小时统计计算返回空 - 空间编码: {}", lcCode);
                    }
                } catch (Exception e) {
                    totalFailCount++;
                    statisticLog.error("生成小时统计失败 - 空间编码: {}, 错误: {}", lcCode, e.getMessage());
                }
            }

            // 4. 批量插入小时统计数据
            statisticLog.info("步骤4: 插入小时统计数据");
            if (!hourStats.isEmpty()) {
                for (PjStatsLocationTemperatureHour stat : hourStats) {
                    try {
                        pjStatsLocationTemperatureHourMapper.insertPjStatsLocationTemperatureHour(stat);
                    } catch (Exception e) {
                        totalFailCount++;
                        totalSuccessCount--; // 从成功计数中移除
                        statisticLog.error("插入小时统计失败 - 空间编码: {}, 错误: {}",
                                stat.getLcCode(), e.getMessage());
                    }
                }
            }

            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            statisticLog.info("=== 空间位置温度小时统计完成 ===");
            statisticLog.info("统计汇总:");
            statisticLog.info("- 总处理空间位置: {} 个", totalSuccessCount + totalFailCount);
            statisticLog.info("- 成功处理: {} 个空间位置", totalSuccessCount);
            statisticLog.info("- 处理失败: {} 个空间位置", totalFailCount);
            statisticLog.info("- 成功率: {}%", (totalSuccessCount + totalFailCount) > 0 ?
                    String.format("%.2f", (totalSuccessCount * 100.0 / (totalSuccessCount + totalFailCount))) : "0.00");
            statisticLog.info("- 总耗时: {} 毫秒", duration);
            statisticLog.info("统计时间: {}", statTime);

        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            long duration = endTime - startTime;

            statisticLog.error("=== 空间位置温度小时统计失败 ===");
            statisticLog.error("错误信息: {}", e.getMessage());
            statisticLog.error("统计时间: {}", statTime);
            statisticLog.error("已成功处理: {} 个空间位置", totalSuccessCount);
            statisticLog.error("处理失败: {} 个空间位置", totalFailCount);
            statisticLog.error("总耗时: {} 毫秒", duration);
            statisticLog.error("异常堆栈:", e);

            log.error("生成空间位置温度小时统计数据失败", e);
            throw new RuntimeException("生成空间位置温度小时统计数据失败", e);
        }
    }

    /**
     * 从分钟统计数据计算小时统计
     */
    private PjStatsLocationTemperatureHour calculateHourStatsFromMinutes(
            List<PjStatsLocationTemperatureMinute> minuteStats, Date hourStart) {

        try {
            if (minuteStats.isEmpty()) {
                return null;
            }

            // 获取基本信息 - 使用第一个统计项的设备信息
            PjStatsLocationTemperatureMinute firstStat = minuteStats.get(0);

            // 计算统计值：最大值取最大、最小值取最小、平均值取所有平均值的平均
            BigDecimal maxTemperature = minuteStats.stream()
                    .map(PjStatsLocationTemperatureMinute::getMaxTemperature)
                    .max(BigDecimal::compareTo)
                    .orElse(BigDecimal.ZERO);

            BigDecimal minTemperature = minuteStats.stream()
                    .map(PjStatsLocationTemperatureMinute::getMinTemperature)
                    .min(BigDecimal::compareTo)
                    .orElse(BigDecimal.ZERO);

            BigDecimal avgTemperature = minuteStats.stream()
                    .map(PjStatsLocationTemperatureMinute::getAvgTemperature)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .divide(BigDecimal.valueOf(minuteStats.size()), 2, RoundingMode.HALF_UP);

            // 构建详细温度数据JSON
            JSONObject tempData = new JSONObject();
            JSONArray maxDataArray = new JSONArray();
            JSONArray minDataArray = new JSONArray();
            JSONArray avgDataArray = new JSONArray();

            for (PjStatsLocationTemperatureMinute minuteStat : minuteStats) {
                JSONObject maxObj = new JSONObject();
                maxObj.put(minuteStat.getStatTime().toString(), minuteStat.getMaxTemperature());
                maxDataArray.add(maxObj);

                JSONObject minObj = new JSONObject();
                minObj.put(minuteStat.getStatTime().toString(), minuteStat.getMinTemperature());
                minDataArray.add(minObj);

                JSONObject avgObj = new JSONObject();
                avgObj.put(minuteStat.getStatTime().toString(), minuteStat.getAvgTemperature());
                avgDataArray.add(avgObj);
            }

            tempData.put("max_temperatures", maxDataArray);
            tempData.put("min_temperatures", minDataArray);
            tempData.put("avg_temperatures", avgDataArray);

            // 创建小时统计记录
            PjStatsLocationTemperatureHour hourStat = new PjStatsLocationTemperatureHour();
            hourStat.setLcCode(firstStat.getLcCode());
            hourStat.setDeviceNo(firstStat.getDeviceNo());
            hourStat.setChannelNo(firstStat.getChannelNo());
            hourStat.setStatTime(hourStart);
            hourStat.setMaxTemperature(maxTemperature);
            hourStat.setMinTemperature(minTemperature);
            hourStat.setAvgTemperature(avgTemperature);
            hourStat.setMarkerCount(minuteStats.stream().mapToInt(PjStatsLocationTemperatureMinute::getMarkerCount).sum());
            hourStat.setSampleCount(minuteStats.stream().mapToInt(PjStatsLocationTemperatureMinute::getSampleCount).sum());
            hourStat.setTemperatureData(tempData.toJSONString());

            return hourStat;

        } catch (Exception e) {
            statisticLog.error("计算小时统计数据失败 - 空间编码: {}, 错误: {}",
                    minuteStats.get(0).getLcCode(), e.getMessage());
            return null;
        }
    }

    /**
     * 根据时间范围删除小时统计数据
     */
    @Override
    public void deleteByTimeRange(Date startTime, Date endTime) {
        statisticLog.info("删除小时统计数据 - 时间范围: {} 到 {}", startTime, endTime);
        try {
            int deletedCount = pjStatsLocationTemperatureHourMapper.deleteByTimeRange(
                    startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                    endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()
            );
            statisticLog.info("成功删除 {} 条小时统计数据", deletedCount);
        } catch (Exception e) {
            statisticLog.error("删除小时统计数据失败 - 时间范围: {} 到 {}, 错误: {}",
                    startTime, endTime, e.getMessage());
            throw new RuntimeException("删除小时统计数据失败", e);
        }
    }

    /**
     * 获取指定时间范围的小时统计数据数量
     */
    @Override
    public int countByTimeRange(Date startTime, Date endTime) {
        try {
            return pjStatsLocationTemperatureHourMapper.countByTimeRange(startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                    endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        } catch (Exception e) {
            statisticLog.error("统计小时数据数量失败 - 时间范围: {} 到 {}, 错误: {}",
                    startTime, endTime, e.getMessage());
            return 0;
        }
    }
}